package com.dingwen.treasure.security.filter;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.dingwen.treasure.base.exception.AbstractBaseRuntimeException;
import com.dingwen.treasure.base.pojo.vo.Result;
import com.dingwen.treasure.base.pojo.vo.ResultGenerator;
import com.dingwen.treasure.security.dto.LoginUser;
import com.dingwen.treasure.security.service.TokenService;
import com.dingwen.treasure.security.utils.SecurityUtils;
import lombok.Cleanup;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * 　JwtAuthenticationTokenFilter: JWT token 过滤器，参考若依实现
 * //TODO 认证异常交由 TreasureAuthenticationEntryPoint 目前没有生效
 * 　@author dingwen
 * 　@date 2022/6/13
 */
@RequiredArgsConstructor
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    /**
     * token 服务
     */
    private final TokenService tokenService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
        try {
            // token有效期比redis用户信息有效期短
            // token校验  通过token获取登录用户信息
            LoginUser loginUser = tokenService.getLoginUser(request);

            if (ObjectUtil.isNotNull(loginUser) && ObjectUtil.isNull(SecurityUtils.getAuthentication())) {
                // 用户存在且认证通过

                // 用户名密码权限的认证信息
                UsernamePasswordAuthenticationToken authenticationToken =
                        new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());

                // 设置detail
                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                // 将认证信息放到security上下文中方便后期使用
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
            chain.doFilter(request, response);
        } catch (Exception e) {
            handleException(e, response);

        }
    }


    /**
     * 过滤器中的异常信息直接已流的形势写出 </br>
     * <p>去除这样受检异常模版代码（编译后也是一样的，只是代码看起来更加优雅简洁了）</p>
     * <pre>
     *
     *      try{
     *
     *      }catch(Exception e){
     *          throw new RuntimeException(e);
     *      }
     *
     * </pre>
     *
     * @param e        e
     * @param response 响应
     * @throws Exception 异常信息
     */
    @SneakyThrows
    @SuppressWarnings("ALL")
    private void handleException(Exception e, HttpServletResponse response) {
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        @Cleanup
        PrintWriter writer = response.getWriter();
        Integer code = HttpStatus.UNAUTHORIZED.value();
        if (e instanceof AbstractBaseRuntimeException) {
            AbstractBaseRuntimeException baseRuntimeException = (AbstractBaseRuntimeException) e;
            code = baseRuntimeException.getCode();
        }
        Result<Object> genFailureResult = ResultGenerator.genFailureResult(e.getMessage(), code);
        writer.write(JSONUtil.toJsonPrettyStr(genFailureResult));
    }
}
